@file:Suppress("unused")

package com.spica.spicaschool.ui.diaryadd

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.*
import android.provider.MediaStore
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation
import com.kongzue.dialogx.dialogs.PopTip
import com.kongzue.dialogx.dialogs.TipDialog
import com.kongzue.dialogx.dialogs.WaitDialog
import com.spica.spicaschool.BuildConfig
import com.spica.spicaschool.R
import com.spica.spicaschool.base.BaseFragment
import com.spica.spicaschool.databinding.FragmentDiaryWriteBinding
import com.spica.spicaschool.network.Url
import com.spica.spicaschool.utils.*
import com.tencent.cos.xml.CosXmlService
import com.tencent.cos.xml.exception.CosXmlClientException
import com.tencent.cos.xml.exception.CosXmlServiceException
import com.tencent.cos.xml.listener.CosXmlResultListener
import com.tencent.cos.xml.model.CosXmlRequest
import com.tencent.cos.xml.model.CosXmlResult
import com.tencent.cos.xml.transfer.COSXMLUploadTask
import com.tencent.cos.xml.transfer.TransferConfig
import com.tencent.cos.xml.transfer.TransferManager
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import rxhttp.wrapper.param.RxHttp
import timber.log.Timber
import java.io.File
import java.io.UnsupportedEncodingException
import java.net.URLEncoder
import java.util.*

/**
 * 添加动态
 */
private const val BUCKET_NAME = "spica-school-1258775535"//存储筒名称
private const val RES_IMAGE = 100

@SuppressLint("SetTextI18n")
class DiaryWriteFragment : BaseFragment<FragmentDiaryWriteBinding>(), CosXmlResultListener {

  private val isAnonymous = true

  private var programPreview = ""//格式化内容

  private var programContent = ""

  private var imageSelected: Uri? = null //存放选中照片的Uri

  //腾讯云对象存储服务
  private lateinit var cosXmlService: CosXmlService

  private lateinit var transferManager: TransferManager
  private var cosxmlTask: COSXMLUploadTask? = null

  private var isFrom = 0//0:表示正常编辑  1:表示是重新编辑

  private var imageWidth = 100

  private val uiHandler: Handler = Handler(Looper.getMainLooper())


  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    initTencentCos()
  }

  /**
   * 初始化腾讯COS
   */
  private fun initTencentCos() {
    cosXmlService = CosServiceFactory.getCosXmlService(
      requireContext(),
      BuildConfig.COS_SECRET_ID,
      BuildConfig.COS_SECRET_KEY,
      true
    )
    val transferConfig = TransferConfig.Builder().build()
    transferManager = TransferManager(cosXmlService, transferConfig)
  }

  private fun initView() {
    AndroidBug5497Workaround.assistActivity(requireActivity())
    val dm = resources.displayMetrics
    imageWidth = dm.widthPixels - 30
    viewBinding.editor.apply {
      setPlaceholder("在这里编辑你的日记")
      setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.colorBack))
      setEditorFontSize(18)
      setEditorFontColor(ContextCompat.getColor(requireContext(), R.color.colorDarkText))
      setPadding(10, 10, 10, 10)
    }
  }

  /**
   * @param progress 已上传文件大小
   * @param total 文件总大小
   */
  private fun refreshUploadProgress(progress: Long, total: Long) {
    val fraction: Float = progress / total * 100.0.toFloat()
    Timber.e("上传进度：${fraction}%")
    lifecycleScope.launch(Dispatchers.Main) {
      WaitDialog.show("上传中...", fraction)
    }
  }


  /**
   * 初始化监听器
   */
  @SuppressLint("SetTextI18n")
  private fun initListener() {
    viewBinding.btnClear.setOnClickListener {
      viewBinding.editor.clearFocusEditor()
    }
    viewBinding.btnImg.setOnClickListener { chooseImage() }
    viewBinding.btnSend.setOnClickListener {
      if (viewBinding.tvTitle.text.isEmpty()) {
        //标题未设定
        Toast.makeText(context, "标题不能为空", Toast.LENGTH_SHORT).show()
        return@setOnClickListener
      }
      if (viewBinding.editor.html.isEmpty()) {
        //输入内容为空
        Toast.makeText(context, "内容不能为空", Toast.LENGTH_SHORT).show()
        return@setOnClickListener
      }


      try {
        programPreview = URLEncoder.encode(programPreview, "utf-8")
        programContent = URLEncoder.encode(
          "<html><head><style>"
              + "body {margin: 0;padding: 0;color: #2F2F2F;letter-spacing: 1px;ont-size: 16px;line-height:22px;}"
              + "img {display: block;max-width: 100%;margin: auto;}"
              + "</style></head><body>${viewBinding.editor.html} </body></html>",
          "utf-8"
        )
      } catch (e: UnsupportedEncodingException) {
        Toast.makeText(requireContext(), "格式化文本错误：${e.message}", Toast.LENGTH_LONG).show()
        e.printStackTrace()
        return@setOnClickListener
      }
      RxHttp.postForm(Url.DIARY_ADD)
        .add(
          "token",
          SpUtils.getSpValue(
            context = requireContext(),
            key = TOKEN_SIGN,
            defaultVal = ""
          )
        )
        .add("type", "5")
        .add("title", viewBinding.tvTitle.text.toString())
        .add("content", programContent)
        .add("pre_content", HtmlUtil.getText(viewBinding.editor.html))
        .add("ano", if (isAnonymous) "0" else "1")
        .add("img", programPreview)
        .asOkResponse()
        .subscribe({
          if (it.code == 200) {
            //TODO
            uiHandler.post {
              Navigation.findNavController(
                requireActivity(),
                R.id.fragment_container_view
              ).popBackStack()
              TipDialog.setMessage("发布成功")
            }
          } else {
            uiHandler.post {
              TipDialog.setMessage(it.message)
            }
          }
        }, {
          uiHandler.post {
            TipDialog.show("运行期间发生异常：${it.message.toString()}")
          }
        })
    }
    viewBinding.editor.setOnTextChangeListener {
      viewBinding.tvTextNum.text = "${HtmlUtil.getText(viewBinding.editor.html).length}字"
      //没有标题不可点击发送
      if (viewBinding.tvTitle.text.isNullOrEmpty() || programPreview.isEmpty()) {
        viewBinding.btnSend.isSelected = false
        viewBinding.btnSend.isEnabled = false
      } else {
        viewBinding.btnSend.isSelected = false
        viewBinding.btnSend.isEnabled = false
      }
      viewBinding.btnSend.isEnabled = true
      viewBinding.editor.setOnDecorationChangeListener { _, types ->
        run {
          val flags = types.map { it.name }
          //是否粗体
          if (flags.contains("BOLD")) {
            viewBinding.btnBold.select(true)
          } else {
            viewBinding.btnBold.select(false)
          }
          //是否斜体
          if (flags.contains("ITALIC")) {
            viewBinding.btnItalic.select(true)
          } else {
            viewBinding.btnItalic.select(false)
          }
          //是否下划线
          if (flags.contains("UNDERLINE")) {
          } else {
          }
          //是否标题
          if (flags.contains("H3")) {
            viewBinding.btnTitle.select(true)
          } else {
            viewBinding.btnTitle.select(false)
          }
          //是否有序列表
          if (flags.contains("ORDEREDLIST")) {
            viewBinding.btnOl.select(true)
          } else {
            viewBinding.btnOl.select(false)
          }
          if (flags.contains("UNORDEREDLIST")) {
            viewBinding.btnUl.select(true)
          } else {
            viewBinding.btnUl.select(false)
          }
        }
      }
    }

    with(viewBinding) {
      btnBold.setOnClickListener { againEdit();editor.setBold() }
      btnItalic.setOnClickListener { againEdit();editor.setItalic() }
      btnOl.setOnClickListener { againEdit();editor.setNumbers() }
      btnTitle.setOnClickListener { againEdit();editor.setHeading(3) }
      btnUl.setOnClickListener { againEdit();editor.setBullets() }
      btnUndo.setOnClickListener {
        editor.focusEditor()
        editor.undo()
      }
      btnRedo.setOnClickListener {
        editor.focusEditor()
        editor.redo()
      }
    }
    viewBinding.editor.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
      if (!hasFocus) {
        //失去焦点时
        //TODO
      } else {
        //获得焦点时
        //TODO
      }
    }
  }

  /**
   * 上传照片
   */
  private fun upload() {
    if (imageSelected == null) {
      Timber.e("imageSelected: 没有需要上传的文件")
      return
    }
    //原进程未结束？？？
    if (cosxmlTask != null) {
      PopTip.show("上传任务未完成，请稍后重试")
      return
    }
    val file = File(
      FilePathHelper.getAbsPathFromUri(
        requireContext(),
        imageSelected
      )
    )
    cosxmlTask = transferManager.upload(
      BUCKET_NAME, MD5Utils.encryptMD5File2String(file),
      file.path, null
    )
    cosxmlTask?.setCosXmlResultListener(this)
    cosxmlTask?.setCosXmlProgressListener { complete, target ->
      refreshUploadProgress(
        complete,
        target
      )
    }

  }

  @Suppress("DEPRECATION")
  private fun chooseImage() {
    startActivityForResult(getPickImageIntent(), RES_IMAGE)
  }

  private fun handleImageRequest(data: Intent?) {
    var imageUri: Uri?
    var queryImageUrl: String
    val exceptionHandler = CoroutineExceptionHandler { _, t ->
      t.printStackTrace()
      Toast.makeText(
        requireContext(),
        t.localizedMessage ?: "发生了一些不可预知的错误，请稍后重试",
        Toast.LENGTH_SHORT
      ).show()
    }

    lifecycleScope.launch(Dispatchers.Main + exceptionHandler) {
      if (data?.data != null) {
        //来自画廊的照片
        imageUri = data.data
        queryImageUrl = imageUri?.path ?: ""
        queryImageUrl =
          requireActivity().compressImageFile(queryImageUrl, false, imageUri!!)
        imageUri = Uri.fromFile(File(queryImageUrl))
        if (queryImageUrl.isNotEmpty()) {
          //url不为空
          imageSelected = imageUri
          upload()
        }
      } else {
        Toast.makeText(requireContext(), "上传图片失败", Toast.LENGTH_SHORT).show()
      }

    }
  }


  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    when (requestCode) {
      RES_IMAGE -> {
        if (resultCode == Activity.RESULT_OK) {
          handleImageRequest(data)
        }
      }
    }
  }

  /**
   * 获取启用原生 相机，相册的Intent
   */
  private fun getPickImageIntent(): Intent {
    var chooserIntent = Intent()
    var intentList: MutableList<Intent> = ArrayList()
    val pickIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
    val takePhotoIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, setImageUri())
    //获取画廊Intent
    intentList = addIntentsToList(requireContext(), intentList, pickIntent)
    //获取相机Intent
    intentList = addIntentsToList(requireContext(), intentList, takePhotoIntent)
    if (intentList.size > 0) {
      chooserIntent = Intent.createChooser(
        intentList.removeAt(intentList.size - 1),
        "选择您想插入的图片"
      )
      chooserIntent.putExtra(
        Intent.EXTRA_INITIAL_INTENTS,
        intentList.toTypedArray<Parcelable>()
      )
    }

    return chooserIntent
  }

  private fun setImageUri(): Uri {
    val imageUri: Uri
    val folder = File("${requireContext().getExternalFilesDir(Environment.DIRECTORY_DCIM)}")
    folder.mkdirs()
    val file = File(folder, "Image_Tmp.jpg")
    if (file.exists())
      file.delete()
    file.createNewFile()
    imageUri = FileProvider.getUriForFile(
      requireContext(),
      BuildConfig.APPLICATION_ID + ".fileProvider",
      file
    )
    return imageUri
  }

  @SuppressLint("QueryPermissionsNeeded")
  private fun addIntentsToList(
    context: Context,
    list: MutableList<Intent>,
    intent: Intent
  ): MutableList<Intent> {
    val resInfo = context.packageManager.queryIntentActivities(intent, 0)
    for (resolveInfo in resInfo) {
      val packageName = resolveInfo.activityInfo.packageName
      val targetedIntent = Intent(intent)
      targetedIntent.setPackage(packageName)
      list.add(targetedIntent)
    }
    return list
  }

  override fun onSuccess(request: CosXmlRequest?, result: CosXmlResult?) {
    lifecycleScope.launch {
      withContext(Dispatchers.Main) {
        Timber.e(result?.accessUrl.toString())
        viewBinding.editor.insertImage(result?.accessUrl, "image")
        WaitDialog.dismiss()
        cosxmlTask = null
      }
    }
  }

  override fun onFail(
    request: CosXmlRequest?,
    exception: CosXmlClientException?,
    serviceException: CosXmlServiceException?
  ) {
    lifecycleScope.launch(Dispatchers.Main) {
      exception?.printStackTrace()
      Log.e("上传失败：", exception.toString())
      TipDialog.show("传输过程发生错误", WaitDialog.TYPE.ERROR)
      cosxmlTask = null
    }
  }

  private fun ImageView.select(boolean: Boolean) {
    if (boolean) {
      setColorFilter(ContextCompat.getColor(requireContext(), R.color.colorPrimary))
    } else {
      setColorFilter(ContextCompat.getColor(requireContext(), R.color.colorDefaultText))
    }
  }

  private fun againEdit() {
    //如果第一次点击工具时候，没有焦点时，获取焦点并弹出软键盘
    viewBinding.editor.focusEditor()
    KeyBoardUtils.openKeybord(viewBinding.tvTitle, requireContext())
  }

  override fun setupViewBinding(
    inflater: LayoutInflater,
    container: ViewGroup?
  ): FragmentDiaryWriteBinding = FragmentDiaryWriteBinding.inflate(inflater, container, false)

  override fun init() {
    initView()
    initListener()
    initTencentCos()
  }

}
